package com.itheima.health.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.itheima.health.common.MessageConst;
import com.itheima.health.dao.MemberDao;
import com.itheima.health.dao.OrderDao;
import com.itheima.health.dao.OrderSettingDao;
import com.itheima.health.entity.Result;
import com.itheima.health.pojo.Member;
import com.itheima.health.pojo.Order;
import com.itheima.health.pojo.OrderSetting;
import com.itheima.health.service.OrderService;
import com.itheima.health.utils.DateUtils;
import com.itheima.health.utils.ZookeeperLock;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;

/**
 * @Author likepei
 * @Date 2020/4/6 23:45
 * @Version v1.0
 * @Description 体检预约业务接口实现类
 */
@Service
@Slf4j
@Transactional
public class OrderServiceImpl implements OrderService {

    //依赖注入
    @Autowired
    private OrderSettingDao orderSettingDao;
    @Autowired
    private MemberDao memberDao;
    @Autowired
    private OrderDao orderDao;

    /**
     * 保存预约订单
     * @param map 页面发过来的数据(体检人, 性别, 手机号,验证码, 身份证号, 体检日期)
     * @return
     */
    @Override
    public Result addOrder(Map<String, String> map) {
        try {
            //控制台 打印 页面传过来的数据
            System.out.println("map = " + map);
            //map = {setmealId=12, idCard=123456789012345678, sex=1, name=晓明, validateCode=21b8, telephone=18500022116, orderDate=2020-04-16}

            //检查预约日期是否做过预约设置
            log.debug(">>>>>>>>>>>>>>>>>>>>>检查预约日期是否做过预约设置");
            //1. 根据日期获取预约设置对象
            Date orderDate = DateUtils.parseString2Date(map.get("orderDate"));
            OrderSetting orderSetting = orderSettingDao.findByOrderDate(orderDate);
            //2. 预约设置对象为空，则没有做预约设置, 返回选择的日期不能预约
            if(orderSetting == null){
                //返回选择的日期不能预约
                return new Result(false, MessageConst.SELECTED_DATE_CANNOT_ORDER);
            }

            //检查预约日期是否已经约满
            log.debug(">>>>>>>>>>>>>>>>>>>>>>>>>>>检查预约日期是否已经约满");
            //获取可预约人数, 获取已预约人数 进行对比, 若已经约满, 返回预约已满
            int number = orderSetting.getNumber(); //可预约人数
            int reservations = orderSetting.getReservations(); //已预约人数
            if(reservations >= number){
                //若已经约满, 返回预约已满
                return new Result(false, MessageConst.ORDER_FULL);
            }


            //检查用户是否为会员
            log.debug(">>>>>>>>>>>>>>>>>>>>>>>检查用户是否为会员");
            //1. 根据手机号获取会员信息
            String telephone = map.get("telephone");
            Member member = memberDao.findByTelephone(telephone);
            //获取套餐id
            int setmealId = Integer.parseInt(map.get("setmealId"));

            if(member != null){
                //2. 如果会员不为空 ，则是会员
                /*
                如果是会员，根据会员ID、预约日期、套餐ID进行查询，
                看是否有预约记录，如果有预约记录直接返回(已经完成预约,不能重复预约)，没有继续执行
                 */
                Integer memberId = member.getId();
                Order order = new Order(null, memberId, orderDate, null, null, setmealId);
                //调用dao, 实现多条件查询
                List<Order> orderList = orderDao.findByCondition(order);
                //看是否有预约记录，如果有直接返回(已经完成预约,不能重复预约)，没有继续执行
                if(orderList != null && orderList.size() >0){
                    return new Result(false, MessageConst.HAS_ORDERED);
                }

            } else {
                //3. 如果会员为空，说明是非会员，则自动注册会员
                member = new Member();
                member.setPhoneNumber(map.get("telephone")); //手机号码
                member.setRegTime( new Date() ); //注册时间
                //调用dao的保存会员方法
                memberDao.add(member);
            }
            //4.更新会员信息
            member.setName( map.get("name") ); //体检人姓名
            member.setSex(map.get("sex")); //性别
            member.setIdCard( map.get("idCard")); //身份证号
            memberDao.update(member);


            //保存体检预约，预约成功
            log.debug(">>>>>>>>>>>>>>>>>>>>>>>保存体检预约，预约成功");
            //封装预约对象，包含会员Id 、预约日期、预约类型、预约状态、套餐ID
            Order order = new Order(null, member.getId(), orderDate, Order.ORDERTYPE_WEIXIN, Order.ORDERSTATUS_NO, setmealId);
            //调用dao, 保存预约订单对象
            orderDao.add(order);

            //更新预约设置，更新预约人数
            log.debug(">>>>>>>>>>>>>>>>>>>>>>>更新预约设置，更新预约人数");
            //获取当前预约人数，在现有人数上加1。
            //加上zookeeper的分布式锁
            Lock lock=new ZookeeperLock();
            lock.lock();
            try {
                orderSetting.setReservations( orderSetting.getReservations() + 1 );
                //调用dao, 更新已预约人数
                orderSettingDao.updateReservations(orderSetting);
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
            return new Result(true, "保存预约订单成功", order);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, MessageConst.ACTION_FAIL);
        }
    }

    /**
     * 基于预约id 获取体检预约成功的信息
     * @param id 预约id
     * @return
     */
    @Override
    public Result findById4Detail(Integer id) {

        try {
            //根据id查询预约信息, 包括体检人信息,套餐信息
            Map<String, Object> map = orderDao.findById4Detail(id);
            //调用日期工具类, 把数据库日期 转换为 字符串
            String orderDate = DateUtils.parseDate2String((Date) map.get("orderDate"));
            map.put("orderDate", orderDate);

            return new Result(true, MessageConst.QUERY_ORDER_SUCCESS, map);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, MessageConst.QUERY_ORDER_FAIL);
        }
    }
}
